package com.kmxd.ams.app.arrange.command;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.kmxd.ams.client.archive.IArchiveFieldSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.ArchiveFieldQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveFieldListVO;
import com.kmxd.ams.client.arrange.IBoxSvc;
import com.kmxd.ams.client.arrange.IProjectSvc;
import com.kmxd.ams.client.arrange.IVolumeSvc;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.DynamicTableNameUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveType;
import com.kmxd.ams.infra.arrange.base.BaseBO;
import com.kmxd.ams.infra.arrange.base.SystemBO;
import com.kmxd.ams.infra.arrange.entity.Box;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Volume;
import com.kmxd.ams.infra.tmpl.dto.ArchTmplBO;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 扩展数据提取
 *
 * @author nickbi
 */
@Slf4j
@Component
@AllArgsConstructor
public class ExtendDataCmd {

  private final IVolumeSvc volumeSvc;
  private final IBoxSvc boxSvc;
  private final IProjectSvc projectSvc;
  private final IArchiveFieldSvc archiveFieldSvc;
  private final IArchiveTypeSvc archiveTypeSvc;
  /**
   * 提前设置继承上级的数据
   *
   * @param req
   */
  public Map<String, Object> buildExtendData(SystemBO req) {
    ArchiveFieldQueryDTO qry = new ArchiveFieldQueryDTO();
    qry.setTableId(req.getTableId());
    qry.setAttrExtends(Boolean.TRUE);
    List<ArchiveFieldListVO> fieldList = archiveFieldSvc.selectList(qry);
    if (ObjectUtil.isEmpty(fieldList)) {
      return Maps.newHashMap();
    }
    Map<String, List<ArchiveFieldListVO>> collect =
        fieldList.stream()
            .filter(f -> Objects.nonNull(f.getExtendsTableId()))
            .collect(Collectors.groupingBy(ArchiveFieldListVO::getExtendsTableId));

    return collect.entrySet().stream()
        .map(
            entry -> {
              if (entry.getKey().contains(ArchTmplBO.VOLUME)) {
                Map<String, Object> volMap =
                    copyExtendsData(
                        req, entry.getKey(), volumeSvc, ArchConst.VOL_ID, entry.getValue());
                if (Objects.isNull(req.getProjId())) {
                  return volMap;
                }

                String projCodeKey = StringUtils.underlineToCamel(ArchConst.PROJ_CODE);
                if (ObjectUtil.isNotEmpty(volMap.get(projCodeKey))) {
                  return volMap;
                }
                // 特殊处理项目级
                ArchiveType archType = archiveTypeSvc.getById(req.getArchTypeId());
                // 看是否为项目级，查询顶级继承数据信息
                Map<String, Object> projMap =
                    copyExtendsData(
                        req,
                        archType.getProjTableId(),
                        projectSvc,
                        ArchConst.PROJ_ID,
                        entry.getValue());
                volMap.put(projCodeKey, projMap.get(projCodeKey));
                return volMap;
              }
              if (entry.getKey().contains(ArchTmplBO.BOX)) {
                return copyExtendsData(
                    req, entry.getKey(), boxSvc, ArchConst.BOX_ID, entry.getValue());
              }
              if (entry.getKey().contains(ArchTmplBO.PROJECT)) {
                return copyExtendsData(
                    req, entry.getKey(), projectSvc, ArchConst.PROJ_ID, entry.getValue());
              }
              return Maps.<String, Object>newHashMap();
            })
        .flatMap(e -> e.entrySet().stream())
        // toMap 因Map merge方法不支持null value所以回报空指针，改为foreach merge
        // https://stackoverflow.com/questions/24630963/nullpointerexception-in-collectors-tomap-with-null-entry-values
        .collect(HashMap::new, (k, v) -> k.put(v.getKey(), v.getValue()), HashMap::putAll);
  }

  public <T> T buildExtendEntity(SystemBO req) {
    Map<String, Object> map = buildExtendData(req);
    if (Objects.isNull(map)) {
      return null;
    }
    return ConvertUtil.toBean(map, getDataClass(req.getTableId()));
  }

  private <T> Class<T> getDataClass(String tableId) {
    if (tableId.contains(ArchTmplBO.DOCUMENT)) {
      return (Class<T>) Document.class;
    }
    if (tableId.contains(ArchTmplBO.BOX)) {
      return (Class<T>) Box.class;
    }
    if (tableId.contains(ArchTmplBO.VOLUME)) {
      return (Class<T>) Volume.class;
    }
    return null;
  }

  private Map<String, Object> copyExtendsData(
      BaseBO req,
      String tableId,
      IService service,
      String dataIdField,
      List<ArchiveFieldListVO> extendFieldList) {
    Map<String, Object> boMap = BeanUtil.beanToMap(req);
    Map<String, Object> resMap = Maps.newHashMap();
    Object dataId = boMap.get(dataIdField);
    if (ObjectUtil.isEmpty(extendFieldList)) {
      return resMap;
    }
    DynamicTableNameUtil.setTableName(tableId);
    Object extendBO = service.getById((Long) dataId);
    if (Objects.isNull(extendBO)) {
      return resMap;
    }
    Map<String, Object> extendMap = BeanUtil.beanToMap(extendBO);
    extendFieldList.forEach(
        extendField -> {
          // 将上级的数据，继承复制到下级数据
          String camelField = StringUtils.underlineToCamel(extendField.getExtendsField());
          // 分类号，分类名称特殊处理
          if (ImmutableSet.of(ArchConst.CLASSFY, ArchConst.CLASSFY_NAME_CAMEL)
              .contains(camelField)) {
            String classfyNameCamel = StringUtils.underlineToCamel(ArchConst.CLASSFY_NAME);
            String classfyCamel = StringUtils.underlineToCamel(ArchConst.CLASSFY);
            resMap.put(classfyCamel, extendMap.get(classfyCamel));
            resMap.put(classfyNameCamel, extendMap.get(classfyNameCamel));
          } else {
            // 将上级继承的数据，赋值到下级对于字段中
            resMap.put(
                StringUtils.underlineToCamel(extendField.getDbFieldKey()),
                extendMap.get(camelField));
          }
        });
    return resMap;
  }
}
